#include <AST/expr/control/WhileAST.hpp>
#include <global.hpp>
#include <AST/expr/var/VarAST.hpp>
#include <AST/expr/literal/BoolAST.hpp>
#include <AST/expr/control/IfAST.hpp>
#include <AST/expr/AnyGenAST.hpp>

While::While(Expr *condition, Expr *body)
    : condition(condition), body(body) {
    // 如果无条件，则永远为true
    if (condition == nullptr) this->condition = new Bool(true);
}

llvm::Value *While::codegen() {
    auto scopeGuard = theScope.guard();
    Function *fun = builder.GetInsertBlock()->getParent();

    // 设置锚点
    BasicBlock *whileCondBlock = BasicBlock::Create(theContext, "whileCond", fun);
    BasicBlock *whileBodyBlock = BasicBlock::Create(theContext, "whileBody");
    BasicBlock *whileEndBlock = BasicBlock::Create(theContext, "whileEnd");
    theScope.setBreakPoint(whileEndBlock);
    theScope.setContinuePoint(whileCondBlock);

    // 显式跳转到循环
    builder.CreateBr(whileCondBlock);

    // 写循环Block
    builder.SetInsertPoint(whileCondBlock);

    // TODO: stack保护外部变量

    builder.CreateCondBr(condition->codegen(), whileBodyBlock, whileEndBlock);

    // 处理循环体
    fun->getBasicBlockList().push_back(whileBodyBlock);
    builder.SetInsertPoint(whileBodyBlock);
    if (body) {
        if (body->codegen() == nullptr)
            return logError("While::codegen: body codegen failed");
    }
    builder.CreateBr(whileCondBlock);

    // 处理循环结束
    fun->getBasicBlockList().push_back(whileEndBlock);
    builder.SetInsertPoint(whileEndBlock);

    // TODO: 还原stack保护外部变量

    // XXX: 正常返回void
    return llvm::UndefValue::get(BasicType::VoidTy);
}